//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2003 Intrinsyc Europe Ltd.
//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2004 Siemens AG
//
// Version: 1.1.2.5
// Date:    11. Jan. 2006
//////////////////////////////////////////////////////////////////////////////
//
//
// (C) Copyright 2007 Marvell International Ltd.
//  All Rights Reserved
//


#include "precomp.h"

//
//
//
BOOL ValidateOpenData(const DWORD dwOpenData, CComHandle*& rpDevice) {
CComInstanceHandle* pHandle = NULL;

  TBD_ASSERT(dwOpenData != 0);

  pHandle = (CComInstanceHandle*)dwOpenData;
  if (pHandle) {
    rpDevice = pHandle->GetDevice();
    TBD_ASSERT(rpDevice != NULL);
    if (rpDevice) {
      if (rpDevice->FHandleIsOwner(pHandle)) {
        return TRUE;
      }
    }
  }

  return FALSE;
}

//
//
// COM driver initialization
//
DWORD VDA_Init(DWORD dwInfo) {

	DWORD dwRet = 0;	

#ifdef RIL_MUX_ENABLE
	return 0;
#endif

	dwRet = (DWORD)g_ComManager.CreatePortDevice((LPWSTR)dwInfo);

	if (!dwRet)
	{
		return dwRet;  
	}

    /* Check if it is need to update register item of data port */
    HKEY hKey = NULL ;
    HKEY hRILKey = NULL ;
	BOOL bUpdateDataPortNameFlag = FALSE ;
    LONG  lStatus ;
    DWORD dwSize;
    DWORD dwDataPortSize;
    DWORD dwValType;

#define MAX_SZKEY_SIZE  256
#define DATA_PORT_MUX_MODE_ITEM  					    TEXT("DataPortMuxMode")
#define DATA_PORT_INTERFACE_ITEM					    TEXT("DataPort")

	wchar_t szName[MAX_SZKEY_SIZE];
	wchar_t szDataPortName[MAX_SZKEY_SIZE];

    /* Update DataPort Item (MUX Mode) to register file for RIL and RIL proxy */    
    lStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, 0, 0, &hRILKey) ;
    if ( ERROR_SUCCESS  != lStatus )
    {
        RILRetailTrace((TEXT("RIL: (VDA): COM_INIT(%s) Failed in RegOpenKeyEx(%s)!\n"), szName, g_tszRegKeyRIL));
		dwRet = 0;
        goto error ;
    }

    dwSize = MAX_SZKEY_SIZE ;
    dwValType = REG_SZ ;
    lStatus = RegQueryValueEx(hRILKey, DATA_PORT_MUX_MODE_ITEM, NULL, &dwValType, (LPBYTE) szName, &dwSize) ;
    if ( ERROR_SUCCESS  != lStatus )
    {
        RILRetailTrace((TEXT("RIL: VDA: COM_INIT Failed in RegQueryValueEx(%s %s)!\n"), szName, DATA_PORT_MUX_MODE_ITEM)) ;
		dwRet = 0;
        goto error ;
    }

    dwDataPortSize = MAX_SZKEY_SIZE ;
    dwValType = REG_SZ ;
    lStatus = RegQueryValueEx(hRILKey, DATA_PORT_INTERFACE_ITEM, NULL, &dwValType, (LPBYTE) szDataPortName, &dwDataPortSize) ;
    if ( ERROR_SUCCESS  != lStatus )
    {
        RILRetailTrace((TEXT("RIL: VDA: COM_INIT Failed in RegQueryValueEx(%s %s)!\n"), szName, DATA_PORT_INTERFACE_ITEM)) ;
		dwRet = 0;
        goto error ;
    }

    bUpdateDataPortNameFlag = FALSE;
    if (dwDataPortSize != dwSize)
	{
		bUpdateDataPortNameFlag = TRUE;
	}
	else
	{
		for (DWORD ulLoopI = 0; ulLoopI < dwDataPortSize; ulLoopI++)
		{
			if (szDataPortName[ulLoopI] != szName[ulLoopI])
			{
				bUpdateDataPortNameFlag = TRUE;
				break;
			}
		}
	}

    if (bUpdateDataPortNameFlag)
	{
		lStatus = RegSetValueEx(hRILKey, DATA_PORT_INTERFACE_ITEM, 0, REG_SZ, (LPBYTE)szName, dwSize);
	    if ( ERROR_SUCCESS  != lStatus )
	    {
	        RILRetailTrace((TEXT("RIL: VDA: COM_INIT Failed in RegSetValueEx(%s %s)!\n"), szName, DATA_PORT_INTERFACE_ITEM)) ;
			dwRet = 0;
	        goto error ;
	    }

		lStatus = RegFlushKey(hRILKey);
	    if ( ERROR_SUCCESS  != lStatus )
	    {
	        RILRetailTrace((TEXT("RIL: VDA: COM_INIT Failed in RegFlushKey!\n"))) ;
			dwRet = NULL;
	        goto error ;
	    }
	}

    RILRetailTrace((TEXT("RIL: VDA: VDA(%s) Successfully!\n"), szName)) ;
	
error:
    if (hRILKey)
	{
		RegCloseKey(hRILKey) ;
	}

	return dwRet;
}

//
// COM driver de-initialization
//
BOOL VDA_Deinit(DWORD dwData) {
  return g_ComManager.DestroyPortDevice((CComHandle*)dwData);
}

//
// Open a COM driver instance
//
DWORD VDA_Open(DWORD dwData, DWORD dwAccess, DWORD dwShareMode) {
CComInstanceHandle*  pHandle = NULL;
CComHandle*          pDevice = (CComHandle*)dwData;

  TBD_ASSERT(dwData != 0);

  if (!pDevice) {
    RILRetailTrace((TEXT("RilDrv: Failed to open application virtual data port (invalid port handle)\r\n")));
    return 0;
  }

  if (!pDevice->IsDownstreamPortOpen()) {
    RILRetailTrace((TEXT("RilDrv: Failed to open application virtual data port (port not open)\r\n")));
    return 0;
  }

  RILRetailTrace((TEXT("RilDrv: Open application virtual data port \"%s\" (%s)\r\n"), g_ComManager.GetPortName(pDevice->GetPortType()), g_ComManager.GetDebugName(pDevice->GetPortType())));

  pHandle = new CComInstanceHandle;
  if (!pHandle || !pHandle->Init(pDevice, dwAccess)) {
    RILRetailTrace((TEXT("RilDrv: Failed to open application virtual data port (falied to create CComInstanceHandle)\r\n")));
    if (pHandle) {
      delete pHandle;
    }
    return 0;
  }

  if (pHandle->IsRsaMode()) {
    if (!g_ComManager.UnlockRsaPort()) {
      RILRetailTrace((TEXT("RilDrv: Failed to unlock RSA port for external usage\r\n")));
      delete pHandle;
      return 0;
    }
  }

  return (DWORD)pHandle;
}

//
// Close a COM driver instance
//
BOOL VDA_Close(DWORD dwOpenData) {
CComInstanceHandle*  pHandle = NULL;

  TBD_ASSERT(0 != dwOpenData);

  RILRetailTrace((TEXT("RilDrv: Close application virtual data port\r\n")));

  pHandle = (CComInstanceHandle*)dwOpenData;
  if (pHandle) {
    if (pHandle->IsRsaMode()) {
      g_ComManager.LockRsaPort(TRUE, FALSE);
    }
    delete pHandle;
    return TRUE;
  }

  return FALSE;
}

//
// COM read
//
DWORD VDA_Read(DWORD dwOpenData, LPVOID pBuf, DWORD len) {
CComHandle* pDevice = NULL;

  TBD_ASSERT(0 != dwOpenData);

  if (!ValidateOpenData(dwOpenData, pDevice)) {
    return 0;
  }

  return g_ComManager.ExternalRead(pDevice->GetPortType(), pBuf, len);
}

//
// COM write
//
DWORD VDA_Write(DWORD dwOpenData, LPCVOID pBuf, DWORD len) {
CComHandle* pDevice = NULL;

  TBD_ASSERT(dwOpenData != 0);

  if (!ValidateOpenData(dwOpenData, pDevice)) {
    return 0;
  }

  return g_ComManager.ExternalWrite(pDevice->GetPortType(), pBuf, len);
}

//
// COM IO-control
//
BOOL VDA_IOControl(DWORD dwOpenData, DWORD dwCode, PBYTE pBufIn, DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut, PDWORD pdwActualOut) {
CComHandle* pDevice = NULL;

  TBD_ASSERT(0 != dwOpenData);

  if (!ValidateOpenData(dwOpenData, pDevice)) {
    return FALSE;
  }

  return g_ComManager.ExternalIoControl(pDevice->GetPortType(), dwCode, pBufIn, dwLenIn, pBufOut, dwLenOut, pdwActualOut);
}

//
// Unimplemented standard interface functions
//
DWORD VDA_Seek(DWORD dwOpenData, long pos, DWORD type) { return (DWORD)-1; }
void VDA_PowerDown(DWORD dwData) { }
void VDA_PowerUp(DWORD dwData) { }

